module fp16_mul #(
    parameter DWIDTH = 16,                      // 数据宽度
    parameter EWIDTH = 5,                       // 指数宽度
    parameter MWIDTH = 10,                      // 尾数宽度
    parameter BIAS   = (1 << (EWIDTH - 1)) - 1  // 偏置值 = 15 = 2^(5-1)-1
) (
    input               clk,
    input               rst_n,
    input  [DWIDTH-1:0] a_operand,  // 操作数A
    input  [DWIDTH-1:0] b_operand,  // 操作数B
    input               valid_in,
    output [DWIDTH-1:0] result,     // 结果
    output              Exception,  // 异常标志
    output              Overflow,   // 溢出标志
    output              Underflow,  // 下溢标志
    output              valid_out
);

    // ================== 流水线级1：输入处理和操作数准备 ==================

    // Stage 1 registers
    reg [DWIDTH-1:0] a_operand_s1, b_operand_s1;
    reg valid_s1;
    reg sign_s1;
    reg [MWIDTH:0] operand_a_s1, operand_b_s1;
    reg [EWIDTH:0] sum_exponent_s1;
    reg a_is_nan_s1, b_is_nan_s1, is_nan_s1;
    reg a_is_inf_s1, b_is_inf_s1, inf_result_s1;
    reg a_is_zero_s1, b_is_zero_s1, zero_s1;
    reg  zero_times_inf_s1;

    // Stage 1 combinational logic
    wire sign_c;
    wire [MWIDTH:0] operand_a_c, operand_b_c;
    wire [EWIDTH:0] sum_exponent_c;
    wire a_is_nan_c, b_is_nan_c, is_nan_c;
    wire a_is_inf_c, b_is_inf_c, inf_result_c;
    wire a_is_zero_c, b_is_zero_c, zero_c;
    wire zero_times_inf_c;

    // 输入处理
    assign sign_c = a_operand[DWIDTH-1] ^ b_operand[DWIDTH-1];

    // 检查NaN
    assign a_is_nan_c = &a_operand[MWIDTH+:EWIDTH] && |a_operand[0+:MWIDTH];
    assign b_is_nan_c = &b_operand[MWIDTH+:EWIDTH] && |b_operand[0+:MWIDTH];
    assign is_nan_c = a_is_nan_c || b_is_nan_c;

    // 检查无穷大
    assign a_is_inf_c = &a_operand[MWIDTH+:EWIDTH] && ~|a_operand[0+:MWIDTH];
    assign b_is_inf_c = &b_operand[MWIDTH+:EWIDTH] && ~|b_operand[0+:MWIDTH];
    assign inf_result_c = a_is_inf_c || b_is_inf_c;

    // 检查零
    assign a_is_zero_c = (a_operand[MWIDTH+:EWIDTH] == 0) && (a_operand[0+:MWIDTH] == 0);
    assign b_is_zero_c = (b_operand[MWIDTH+:EWIDTH] == 0) && (b_operand[0+:MWIDTH] == 0);
    assign zero_c = a_is_zero_c || b_is_zero_c;

    // 检查0乘以无穷大的情况
    assign zero_times_inf_c = (a_is_inf_c && (b_operand == 0)) || (b_is_inf_c && (a_operand == 0));

    // 操作数处理（含隐藏位）
    assign operand_a_c = (|a_operand[MWIDTH+:EWIDTH]) ? {1'b1, a_operand[0+:MWIDTH]} : {1'b0, a_operand[0+:MWIDTH]};
    assign operand_b_c = (|b_operand[MWIDTH+:EWIDTH]) ? {1'b1, b_operand[0+:MWIDTH]} : {1'b0, b_operand[0+:MWIDTH]};

    // 指数求和
    assign sum_exponent_c = a_operand[MWIDTH+:EWIDTH] + b_operand[MWIDTH+:EWIDTH];

    // Stage 1 registers
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            a_operand_s1      <= 0;
            b_operand_s1      <= 0;
            valid_s1          <= 0;
            sign_s1           <= 0;
            operand_a_s1      <= 0;
            operand_b_s1      <= 0;
            sum_exponent_s1   <= 0;
            a_is_nan_s1       <= 0;
            b_is_nan_s1       <= 0;
            is_nan_s1         <= 0;
            a_is_inf_s1       <= 0;
            b_is_inf_s1       <= 0;
            inf_result_s1     <= 0;
            a_is_zero_s1      <= 0;
            b_is_zero_s1      <= 0;
            zero_s1           <= 0;
            zero_times_inf_s1 <= 0;
        end else begin
            a_operand_s1      <= a_operand;
            b_operand_s1      <= b_operand;
            valid_s1          <= valid_in;
            sign_s1           <= sign_c;
            operand_a_s1      <= operand_a_c;
            operand_b_s1      <= operand_b_c;
            sum_exponent_s1   <= sum_exponent_c;
            a_is_nan_s1       <= a_is_nan_c;
            b_is_nan_s1       <= b_is_nan_c;
            is_nan_s1         <= is_nan_c;
            a_is_inf_s1       <= a_is_inf_c;
            b_is_inf_s1       <= b_is_inf_c;
            inf_result_s1     <= inf_result_c;
            a_is_zero_s1      <= a_is_zero_c;
            b_is_zero_s1      <= b_is_zero_c;
            zero_s1           <= zero_c;
            zero_times_inf_s1 <= zero_times_inf_c;
        end
    end

    // ================== 流水线级2：Booth乘法器运算 ==================

    // Stage 2 registers
    reg [DWIDTH-1:0] a_operand_s2, b_operand_s2;
    reg            valid_s2;
    reg            sign_s2;
    reg [EWIDTH:0] sum_exponent_s2;
    reg is_nan_s2, inf_result_s2, zero_s2;
    reg                 zero_times_inf_s2;
    reg  [2*MWIDTH+1:0] product_s2;

    // Stage 2 combinational logic
    wire [        11:0] mult_operand_a = {1'b0, operand_a_s1};  // 扩展到12位
    wire [        11:0] mult_operand_b = {1'b0, operand_b_s1};  // 扩展到12位
    wire [        23:0] mult_product;
    wire [2*MWIDTH+1:0] product_c;

    // Booth乘法器
    booth_mult_12bit booth_multiplier (
        .operand_a(mult_operand_a),
        .operand_b(mult_operand_b),
        .product  (mult_product)
    );

    // 取有效位
    assign product_c = mult_product[2*MWIDTH+1:0];

    // Stage 2 registers
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            a_operand_s2      <= 0;
            b_operand_s2      <= 0;
            valid_s2          <= 0;
            sign_s2           <= 0;
            sum_exponent_s2   <= 0;
            is_nan_s2         <= 0;
            inf_result_s2     <= 0;
            zero_s2           <= 0;
            zero_times_inf_s2 <= 0;
            product_s2        <= 0;
        end else begin
            a_operand_s2      <= a_operand_s1;
            b_operand_s2      <= b_operand_s1;
            valid_s2          <= valid_s1;
            sign_s2           <= sign_s1;
            sum_exponent_s2   <= sum_exponent_s1;
            is_nan_s2         <= is_nan_s1;
            inf_result_s2     <= inf_result_s1;
            zero_s2           <= zero_s1;
            zero_times_inf_s2 <= zero_times_inf_s1;
            product_s2        <= product_c;
        end
    end

    // ================== 流水线级3：规格化、舍入和最终结果 ==================

    // Stage 3 registers
    reg [DWIDTH-1:0] result_s3;
    reg Exception_s3, Overflow_s3, Underflow_s3;
    reg                 valid_s3;

    // Stage 3 combinational logic
    wire                normalized_c;
    wire [2*MWIDTH+1:0] product_normalized_c;
    wire guard_c, round_c, sticky_c, round_up_c;
    wire [MWIDTH:0] product_mantissa_c;
    wire [EWIDTH:0] exponent_c;
    wire Overflow_c, Underflow_c, Exception_c;
    wire [DWIDTH-1:0] result_c;

    // 规格化
    assign normalized_c = product_s2[2*MWIDTH+1];
    assign product_normalized_c = normalized_c ? product_s2 : product_s2 << 1;

    // 舍入处理 - "就近舍入到偶数"
    assign guard_c = product_normalized_c[MWIDTH];
    assign round_c = product_normalized_c[MWIDTH-1];
    assign sticky_c = |product_normalized_c[MWIDTH-2:0];
    assign round_up_c = guard_c & (round_c | sticky_c | product_normalized_c[MWIDTH+1]);

    assign product_mantissa_c = product_normalized_c[MWIDTH+1+:MWIDTH] + round_up_c;

    // 指数计算
    assign exponent_c = sum_exponent_s2 - BIAS + normalized_c + product_mantissa_c[MWIDTH];

    // 异常判断
    assign Overflow_c = ((exponent_c[EWIDTH] & !exponent_c[EWIDTH-1]) & !zero_s2) && !is_nan_s2;
    assign Underflow_c = ((exponent_c[EWIDTH] & exponent_c[EWIDTH-1]) & !zero_s2) ? 1'b1 : 1'b0;
    assign Exception_c = is_nan_s2 || inf_result_s2 || zero_times_inf_s2;

    // 结果输出
    assign result_c = is_nan_s2 || zero_times_inf_s2 ? {1'b0, {EWIDTH{1'b1}}, 1'b1, {(MWIDTH - 1) {1'b0}}} :  // NaN
        inf_result_s2 ? {sign_s2, {EWIDTH{1'b1}}, {MWIDTH{1'b0}}} :  // Infinity
        zero_s2 ? {sign_s2, {(DWIDTH - 1) {1'b0}}} :  // Zero
        Overflow_c ? {sign_s2, {EWIDTH{1'b1}}, {MWIDTH{1'b0}}} :  // Overflow to Infinity
        Underflow_c ? {sign_s2, {(DWIDTH - 1) {1'b0}}} :  // Underflow to Zero
        {sign_s2, exponent_c[0+:EWIDTH], product_mantissa_c[MWIDTH-1:0]};  // Normal result

    // Stage 3 registers
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            result_s3    <= 0;
            Exception_s3 <= 0;
            Overflow_s3  <= 0;
            Underflow_s3 <= 0;
            valid_s3     <= 0;
        end else begin
            result_s3    <= result_c;
            Exception_s3 <= Exception_c;
            Overflow_s3  <= Overflow_c;
            Underflow_s3 <= Underflow_c;
            valid_s3     <= valid_s2;
        end
    end

    // 输出赋值
    assign result    = result_s3;
    assign Exception = Exception_s3;
    assign Overflow  = Overflow_s3;
    assign Underflow = Underflow_s3;
    assign valid_out = valid_s3;

endmodule
